package com.xiao.uitl.es;

import com.alibaba.fastjson.JSON;
import com.xiao.mapper.ArticleMapper;
import com.xiao.pojo.Article;
import com.xiao.service.ArticleService;
import com.xiao.uitl.constant.ESConstants;
import org.apache.lucene.util.QueryBuilder;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.TimeUnit;

@Component
public class ESUtil {
    @Autowired
    @Qualifier("restHighLevelClient")
    RestHighLevelClient ES_Client;

    @Autowired
    ArticleMapper articleMapper;

    public  String init() throws IOException {
        // 初始化时把 数据库中的文章，都放入 ES 中
        System.out.println("hello CommandLineRunner");

        List<Article> allArticle = articleMapper.selectList(null);
        StringJoiner stringJoiner = new StringJoiner("] [","[","]");

        // 如果存在则删除
        if (indexExists(ESConstants.ES_ARTICLE_INDEX)){
            // 删除索引
            boolean delResult = this.deleteIndex(ESConstants.ES_ARTICLE_INDEX);
            stringJoiner.add("删除结果: "+delResult);
        }

        // 添加数据到索引
        String pushResult = this.pushInEs(ESConstants.ES_ARTICLE_INDEX,allArticle);

        stringJoiner.add("push结果: "+pushResult);

        return stringJoiner.toString();

    }


    // 搜索
    public String search(String keyword) throws IOException {
        // 1. 创建搜索请求
        SearchRequest searchRequest = new SearchRequest(ESConstants.ES_ARTICLE_INDEX);
        // 2. 构建搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        // 设置超时 3s
        sourceBuilder.timeout(new TimeValue(3, TimeUnit.SECONDS));


        // ---------- 高亮 【设置】 Start ----------
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("content");
        highlightBuilder.field("title");
        highlightBuilder.requireFieldMatch(true);// 全高亮
        highlightBuilder.preTags("<span style='color:red;'>");// 前缀
        highlightBuilder.postTags("</span>");// 后缀

        // 文章很大 限制展示的搜索结果
        highlightBuilder.fragmentSize(50); // 每个高亮片段的最大字符数
        highlightBuilder.numOfFragments(3); // 从字段中提取的最大片段数

        sourceBuilder.highlighter(highlightBuilder);// 装载到搜索构建中
        // ---------- 高亮 【设置】 End ----------

        // 查询条件

        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, "content", "title")

            .type("most_fields")  // 使用 most_fields 类型
            .operator(Operator.AND)  // 所有词都必须出现在字段中
            .minimumShouldMatch("50%");  // 至少匹配50%的查询词

        sourceBuilder.query(multiMatchQueryBuilder);

        // 设置分页
        sourceBuilder.from(0); sourceBuilder.size(2);

        // 3. 搜索条件封装到 搜索请求中
        searchRequest.source(sourceBuilder);

        // 4. 发起请求
        SearchResponse search = ES_Client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = search.getHits();

        ArrayList<Map<String,Object>> arrayList = new ArrayList<>();
//
//        for (SearchHit hit : hits) {
//            arrayList.add(hit.getSourceAsMap());
//        }

        SearchHit[] hits1 = hits.getHits();

        for (SearchHit hit : hits1) {
            Map<String, Object> asMap = hit.getSourceAsMap();

            System.out.println(asMap.toString());
            // ---------- 高亮 【解析】 Start ----------
            // 1. 获取高亮的数据
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();

            HighlightField highlightContent = highlightFields.get("content");// 高亮的字段

            if (highlightContent!=null){ // 把片段拼成 string
                Text[] fragments = highlightContent.fragments();

                String str="";

                for (Text fragment : fragments) {
                    str+=fragment;
                }
                asMap.put("content",str);

            }

            HighlightField highlightFieldTitle = highlightFields.get("title");// 高亮的字段

            if (highlightFieldTitle!=null){ // 把片段拼成 string
                Text[] fragments = highlightFieldTitle.fragments();

                String str="";

                for (Text fragment : fragments) {
                    str+=fragment;
                }
                asMap.put("title",str);
            }

            arrayList.add(asMap);

        }

        return JSON.toJSONString(arrayList);
    }



    // 查询索引是否存在
    public boolean indexExists(String indexName) throws IOException {
        // 创建一个  get 索引请求
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);

        boolean exists = ES_Client.indices().exists(getIndexRequest,RequestOptions.DEFAULT);

        return exists;
    }

    // 添加数据到索引
    public String pushInEs(String indexName,List list) throws IOException {
        // 1. 创建批量请求
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("1m");// 超时时间 1分钟

        for (int i = 0; i < list.size(); i++) {
            bulkRequest.add(
                    new IndexRequest(indexName)

                            .source(JSON.toJSONString(list.get(i)), XContentType.JSON)// 具体数据,数据类型
            );
        }
        // 2. 发起请求
        BulkResponse bulk = ES_Client.bulk(bulkRequest, RequestOptions.DEFAULT);

        int status = bulk.status().getStatus();

        String result = Integer.toString(status);

        return  result;
    }


    // 删除索引
    public boolean deleteIndex(String indexName) throws IOException {

        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);

        AcknowledgedResponse delete = ES_Client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);

        boolean result = delete.isAcknowledged();
        return result;
    }


}
